(function() {
  var __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

  if (!window.Moshu) {
    window.Moshu = new Object();
  }

  window.Moshu.Canvas2D = new Object();

  window.Moshu.Canvas2D.Vertex = (function(_super) {

    __extends(Vertex, _super);

    function Vertex(x, y) {
      Vertex.__super__.constructor.apply(this, arguments);
      this.x = x;
      this.y = y;
      this.push(x);
      this.push(y);
    }

    Vertex.prototype.set = function(x, y) {
      this.x = x;
      this.y = y;
      this[0] = x;
      return this[1] = y;
    };

    Vertex.prototype.copy = function(vertex) {
      return this.set(vertex[0], vertex[1]);
    };

    return Vertex;

  })(Array);

  window.Moshu.Canvas2D.Vector = (function() {

    function Vector(vector) {
      this.vector = vector;
    }

    Vector.prototype.substract = function(vector) {
      var i, self, x, _i, _len, _ref, _results;
      if (!this.vector || !this.vector.length) {
        return null;
      } else {
        if (!vector || !vector.length || !vector.length === this.vector.length) {
          return null;
        } else {
          self = this;
          _ref = this.vector;
          _results = [];
          for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
            x = _ref[i];
            _results.push(this.vector[i] -= vector[i]);
          }
          return _results;
        }
      }
    };

    Vector.prototype.invert = function() {
      var aux, i, v, _i, _len, _ref, _results;
      _ref = this.vector;
      _results = [];
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
        v = _ref[i];
        if (i < this.vector.length / 2) {
          aux = this.vector[i];
          this.vector[i] = this.vector[this.vector.length - 1 - i];
          _results.push(this.vector[this.vector.length - 1 - i] = aux);
        } else {
          _results.push(void 0);
        }
      }
      return _results;
    };

    Vector.prototype.perp = function() {
      this.invert();
      return this.vector[0] = -this.vector[0];
    };

    Vector.prototype.dotProduct = function(vector) {
      var dot, i, self, v, _i, _len, _ref;
      if (!this.vector || !this.vector.length) {
        return 0;
      } else {
        if (!vector || !vector.length || !vector.length === this.vector.length) {
          return 0;
        } else {
          dot = 0;
          self = this;
          _ref = this.vector;
          for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
            v = _ref[i];
            dot += this.vector[i] * vector[i];
          }
          return dot;
        }
      }
    };

    return Vector;

  })();

  window.Moshu.Canvas2D.Matrix = (function(_super) {

    __extends(Matrix, _super);

    function Matrix() {
      var i, _i;
      for (i = _i = 0; _i <= 3; i = ++_i) {
        this.push(0);
      }
    }

    return Matrix;

  })(Array);

  window.Moshu.Canvas2D.Collision = (function() {

    function Collision(collider, collidee, collisionVector) {
      this.collider = collider;
      this.collidee = collidee;
      this.collisionVector = collisionVector;
    }

    Collision.prototype.recover = function() {};

    return Collision;

  })();

  window.Moshu.Canvas2D.Rotation = (function() {

    function Rotation(centerx, centery, angle) {
      var cosAngle, sinAngle;
      this.center = new Moshu.Canvas2D.Vertex(centerx, centery);
      this.matrix = new Moshu.Canvas2D.Matrix();
      cosAngle = Math.cos(angle);
      sinAngle = Math.sin(angle);
      this.matrix[0] = cosAngle;
      this.matrix[1] = -sinAngle;
      this.matrix[2] = sinAngle;
      this.matrix[3] = cosAngle;
      this.offset = new Moshu.Canvas2D.Vertex(centerx, centery);
    }

    Rotation.prototype.apply = function(vertex) {};

    return Rotation;

  })();

  window.Moshu.Canvas2D.PhysicalObject = (function(_super) {

    __extends(PhysicalObject, _super);

    function PhysicalObject() {
      PhysicalObject.__super__.constructor.apply(this, arguments);
      this.mass = 0;
      this.elasticity = 0;
      this.mediumFrictionCoef = 0;
      this.objectFrictionCoef = 0;
      this.velocity = {
        dx: 0,
        dy: 0
      };
      this.acceleration = {
        ax: 0,
        ay: 0
      };
      this.fixed = true;
    }

    PhysicalObject.prototype.getMomentum = function() {
      var energy;
      energy = {
        ox: 0,
        oy: 0
      };
      if (!this.fixed) {
        energy = {
          ex: this.mass * this.velocity.dx,
          ey: this.mass * this.velocity.dy
        };
      }
      return energy;
    };

    PhysicalObject.prototype.setMomentum = function(momentum) {
      if (this.fixed) {
        this.velocity.dx = 0;
        this.velocity.dy = 0;
      }
      this.velocity.dx = momentum.ox / this.mass;
      return this.velocity.dy = momentum.oy / this.mass;
    };

    return PhysicalObject;

  })(Moshu.Observable);

  window.Moshu.Canvas2D.Shape = (function(_super) {

    __extends(Shape, _super);

    function Shape() {
      Shape.__super__.constructor.call(this);
      this.id = new Date().getTime();
      this.zIndex = 1;
      this.scene = null;
      this.visible = true;
      this.isShape = true;
      this.fixed = false;
      this.stroke = {
        enabled: true,
        width: 1,
        color: "#000"
      };
      this.fill = {
        enabled: false,
        color: "#fff"
      };
    }

    Shape.prototype.setFillStyles = function() {
      var ctx;
      ctx = this.getContext();
      if (this.fill.enabled) {
        return ctx.fillStyle = this.fill.color;
      } else {
        return ctx.fillStyle = null;
      }
    };

    Shape.prototype.setStrokeStyles = function() {
      var ctx;
      ctx = this.getContext();
      if (this.stroke.enabled) {
        ctx.lineWidth = this.stroke.width;
        return ctx.strokeStyle = this.stroke.color;
      } else {
        return ctx.lineWidth = 0;
      }
    };

    Shape.prototype.setStyles = function() {
      this.setStrokeStyles();
      this.setFillStyles();
      return true;
    };

    Shape.prototype.drawCommand = function() {
      var ctx;
      ctx = this.getContext();
      if (ctx) {
        if (this.stroke.enabled) {
          ctx.stroke();
        }
        if (this.fill.enabled) {
          return ctx.fill();
        }
      }
    };

    Shape.prototype.getContext = function() {
      if (this.scene) {
        return this.scene.context;
      } else {
        return null;
      }
    };

    Shape.prototype.timeUpdate = function(dt) {};

    Shape.prototype.draw = function() {};

    return Shape;

  })(Moshu.Canvas2D.PhysicalObject);

  window.Moshu.Canvas2D.Scene = (function(_super) {

    __extends(Scene, _super);

    function Scene(canvasId) {
      this.canvasId = canvasId;
      Scene.__super__.constructor.apply(this, arguments);
      this._shapes = [];
      this.canvas = document.getElementById(this.canvasId);
      this.context = this.canvas.getContext("2d");
      window.Moshu.AnimationManager.bind(this, this.timeUpdate);
      this.collisionManager = new Moshu.Canvas2D.CollisionManager();
    }

    Scene.prototype.add = function(shape) {
      if (shape && shape.isShape) {
        this._shapes.push(shape);
        return shape.scene = this;
      }
    };

    Scene.prototype.remove = function(shape) {
      var i, s, _i, _len, _ref;
      _ref = this._shapes;
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
        s = _ref[i];
        if (s === shape) {
          this._shapes.splice(i, 1);
          shape.scene = null;
          break;
        }
      }
      return shape;
    };

    Scene.prototype.removeById = function(shapeId) {
      var i, s, _i, _len, _ref;
      _ref = this._shapes;
      for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
        s = _ref[i];
        if (s.id === shapeId) {
          this._shapes.splice(i, 1);
          break;
        }
      }
      return shape;
    };

    Scene.prototype.clear = function() {
      this._shapes = [];
      return this.update();
    };

    Scene.prototype.shapes = function() {
      return this._shapes;
    };

    Scene.prototype.update = function() {
      var s, _i, _len, _ref, _results;
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      _ref = this._shapes;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        s = _ref[_i];
        if (s.visible) {
          _results.push(s.draw());
        } else {
          _results.push(void 0);
        }
      }
      return _results;
    };

    Scene.prototype.invalidate = function() {
      return this.update();
    };

    Scene.prototype.timeUpdate = function(dt) {
      var shape, _i, _len, _ref;
      _ref = this._shapes;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        shape = _ref[_i];
        if (shape && !shape.fixed) {
          shape.timeUpdate(dt);
        }
      }
      return this.update();
    };

    Scene.prototype.getBoundaryCollisions = function(shape) {
      var aAboveB, aBelowB, aLeftOfB, aRightOfB, arr, b1, b2, i, maxAx, maxAy, maxBx, maxBy, minAx, minAy, minBx, minBy, s, _i, _len, _ref;
      arr = [];
      if (shape && shape.boundary) {
        _ref = this._shapes;
        for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
          s = _ref[i];
          if (!(shape === s) && s.boundary()) {
            b1 = shape.boundary();
            b2 = s.boundary();
            minAx = b1[0];
            minAy = b1[1];
            maxAx = b1[2];
            maxAy = b1[3];
            minBx = b2[0];
            minBy = b2[1];
            maxBx = b2[2];
            maxBy = b2[3];
            aLeftOfB = maxAx < minBx;
            aRightOfB = minAx > maxBx;
            aAboveB = minAy > maxBy;
            aBelowB = maxAy < minBy;
            if (!(aLeftOfB || aRightOfB || aAboveB || aBelowB)) {
              arr.push(s);
            }
          }
        }
      }
      return arr;
    };

    Scene.prototype.getCollisions = function(shape) {
      var boundaryCollisions, c, col, collisions, _i, _len;
      boundaryCollisions = this.getBoundaryCollisions(shape);
      collisions = [];
      for (_i = 0, _len = boundaryCollisions.length; _i < _len; _i++) {
        c = boundaryCollisions[_i];
        col = this.collisionManager.checkCollide(shape, c);
        if (col) {
          collisions.push(col);
        }
      }
      return collisions;
    };

    return Scene;

  })(Moshu.Observable);

  window.Moshu.Canvas2D.Polygon = (function(_super) {

    __extends(Polygon, _super);

    function Polygon(vertices) {
      Polygon.__super__.constructor.apply(this, arguments);
      this._boundary = [0, 0, 0, 0];
      this._vertices = [];
      this.center = new Moshu.Canvas2D.Vertex(0, 0);
      this._position = new Moshu.Canvas2D.Vertex(0, 0);
      this.vertices(vertices);
      if (this._vertices && this._vertices.length && this._vertices.length > 0) {
        this._position.copy(this._vertices[0]);
      }
      this.isClosed = false;
      this.isPolygon = true;
      this.collisions = [];
    }

    Polygon.prototype.vertices = function(vertices) {
      var args, elem, vertex, _i, _len;
      if (!vertices) {
        return this._vertices;
      } else {
        if (vertices && vertices.length) {
          this._vertices = [];
          for (_i = 0, _len = vertices.length; _i < _len; _i++) {
            elem = vertices[_i];
            vertex = null;
            if (elem && elem.length && elem.length === 2) {
              vertex = new Moshu.Canvas2D.Vertex(elem[0], elem[1]);
            } else {
              if (elem && elem.x && elem.y) {
                vertex = new Moshu.Canvas2D.Vertex(elem.x, elem.y);
              }
            }
            if (vertex) {
              this._vertices.push(vertex);
            }
          }
          args = {
            target: this,
            property: "vertices",
            newValue: this._vertices
          };
          this.updateBoundary();
          this.updateCenter();
          return this.notify("property-changed", args);
        }
      }
    };

    Polygon.prototype.position = function(newPos) {
      var args, newx, newy;
      if (newPos) {
        if (newPos.length && newPos.length === 2) {
          newx = newPos[0];
          newy = newPos[1];
        } else {
          if (newPos.x && newPos.y) {
            newx = newPos.x;
            newy = newPos.y;
          }
        }
        if (!(this._position.x === newx && this._position.y === newy)) {
          this._position.set(newx, newy);
          args = {
            target: this,
            property: "position",
            newValue: this._position
          };
          this.notify("property-changed", args);
          this.updateBoundary();
          this.updateCenter();
        }
      }
      return this._position;
    };

    Polygon.prototype.move = function(dx, dy) {
      var args, elem, p, _i, _len, _ref;
      _ref = this._vertices;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        elem = _ref[_i];
        elem.set(elem.x + dx, elem.y + dy);
      }
      p = this.position();
      this.position([p.x + dx, p.y + dy]);
      if (this.scene) {
        this.collisions = this.scene.getCollisions(this);
      }
      args = {
        target: this,
        x: p.x + dx,
        y: p.y + dy
      };
      return this.notify("moved", args);
    };

    Polygon.prototype.rotate = function(angle, rotationCenter) {
      var args, centerX, centerY, cosAngle, dx, dy, sinAngle, vertex, _i, _len, _ref;
      if (angle && angle !== 0) {
        centerX = null;
        centerY = null;
        if (!rotationCenter) {
          centerX = this.center.x;
          centerY = this.center.y;
        } else {
          if (rotationCenter && rotationCenter.length && rotationCenter.length === 2) {
            centerX = rotationCenter[0];
            centerY = rotationCenter[1];
          } else {
            if (rotationCenter && rotationCenter.x && rotationCenter.y) {
              centerX = rotationCenter.x;
              centerY = rotationCenter.y;
            }
          }
        }
        if (centerX && centerY) {
          cosAngle = Math.cos(angle);
          sinAngle = Math.sin(angle);
          _ref = this.vertices();
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            vertex = _ref[_i];
            dx = vertex.x - centerX;
            dy = vertex.y - centerY;
            vertex.set(centerX + dx * cosAngle - dy * sinAngle, centerY + dx * sinAngle + dy * cosAngle);
          }
          this.updateBoundary();
          this.updateCenter();
          args = {
            target: this,
            rotatedBy: angle,
            centerX: centerX,
            centerY: centerY
          };
          return this.notify("on-rotated", args);
        }
      }
    };

    Polygon.prototype.boundary = function() {
      return this._boundary;
    };

    Polygon.prototype.updateBoundary = function() {
      var elem, maxx, maxy, minx, miny, _i, _len, _ref;
      if (this._vertices && this._vertices.length) {
        minx = null;
        maxx = null;
        miny = null;
        maxy = null;
        _ref = this._vertices;
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          elem = _ref[_i];
          if (elem[0] < minx || !minx) {
            minx = elem[0];
          }
          if (elem[0] > maxx || !maxx) {
            maxx = elem[0];
          }
          if (elem[1] < miny || !miny) {
            miny = elem[1];
          }
          if (elem[1] > maxy || !maxy) {
            maxy = elem[1];
          }
        }
        this._boundary = [minx, miny, maxx, maxy];
      } else {
        this._boundary = [0, 0, 0, 0];
      }
      return this._boundary;
    };

    Polygon.prototype.updateCenter = function() {
      var elem, totalx, totaly, _i, _len, _ref;
      if (this._vertices && this._vertices.length && this._vertices.length > 0) {
        totalx = 0;
        totaly = 0;
        _ref = this._vertices;
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          elem = _ref[_i];
          totalx += elem[0];
          totaly += elem[1];
        }
        this.center.set(totalx / this._vertices.length, totaly / this._vertices.length);
      } else {
        this.center.set(0, 0);
      }
      return this.center;
    };

    Polygon.prototype.timeUpdate = function(dt) {
      var args, cancel, dx, dy, pos;
      if (!this.fixed) {
        dt = dt / 1000;
        this.velocity.dx += this.acceleration.ax * dt;
        this.velocity.dy += this.acceleration.ay * dt;
        pos = this.position();
        dx = this.velocity.dx * dt;
        dy = this.velocity.dy * dt;
        args = {
          target: this,
          x: pos.x + dx,
          y: pos.y,
          dt: dt
        };
        cancel = !this.notify("moving", args);
        if (cancel) {
          dx = 0;
        } else {
          this.move(dx, 0);
          if (this.collisions.length > 0) {
            this.notify("collision", this);
            this.move(-dx, 0);
          }
        }
        args = {
          target: this,
          x: pos.x + dx,
          y: pos.y + dy,
          dt: dt
        };
        cancel = !this.notify("moving", args);
        if (cancel) {
          return dy = 0;
        } else {
          this.move(0, dy);
          if (this.collisions.length > 0) {
            this.notify("collision", this);
            return this.move(0, -dy);
          }
        }
      }
    };

    Polygon.prototype.draw = function() {
      var ctx, i, self, vertex, vertices, _i, _len;
      ctx = this.getContext();
      if (ctx) {
        this.setStyles();
        ctx.beginPath();
        self = this;
        vertices = this.vertices();
        for (i = _i = 0, _len = vertices.length; _i < _len; i = ++_i) {
          vertex = vertices[i];
          if (i === 0) {
            ctx.moveTo(vertex.x, vertex.y);
          } else {
            ctx.lineTo(vertex.x, vertex.y);
          }
        }
        if (this.isClosed) {
          if (vertices.length > 2) {
            ctx.lineTo(vertices[vertices.length - 1].x, vertices[vertices.length - 1].x);
          }
        }
        ctx.closePath();
        return this.drawCommand();
      }
    };

    return Polygon;

  })(Moshu.Canvas2D.Shape);

  window.Moshu.Canvas2D.RegularPolygon = (function(_super) {

    __extends(RegularPolygon, _super);

    function RegularPolygon(x, y, radius, rank) {
      var i, vertex, vertices, _i, _ref;
      vertices = [];
      for (i = _i = 0, _ref = rank - 1; _i <= _ref; i = _i += 1) {
        x = (Math.sin(i / rank * 2 * Math.PI) * radius) + x;
        y = (Math.cos(i / rank * 2 * Math.PI) * radius) + y;
        vertex = [x, y];
        vertices.push(vertex);
      }
      RegularPolygon.__super__.constructor.call(this, vertices);
    }

    return RegularPolygon;

  })(Moshu.Canvas2D.Polygon);

  window.Moshu.Canvas2D.Line = (function(_super) {

    __extends(Line, _super);

    function Line(x, y, width, height) {
      Line.__super__.constructor.call(this, [[x, y], [x + width, y + height]]);
      this.isClosed = false;
    }

    return Line;

  })(Moshu.Canvas2D.Polygon);

  window.Moshu.Canvas2D.Triangle = (function(_super) {

    __extends(Triangle, _super);

    function Triangle(x1, y1, x2, y2, x3, y3) {
      Triangle.__super__.constructor.call(this, [[x1, y1], [x2, y2], [x3, y3]]);
    }

    return Triangle;

  })(Moshu.Canvas2D.Polygon);

  window.Moshu.Canvas2D.Rectangle = (function(_super) {

    __extends(Rectangle, _super);

    function Rectangle(x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      Rectangle.__super__.constructor.call(this, [[this.x, this.y], [this.x + this.width, this.y], [this.x + this.width, this.y + this.height], [this.x, this.y + this.height]]);
    }

    return Rectangle;

  })(Moshu.Canvas2D.Polygon);

  window.Moshu.Canvas2D.CanvasImage = (function(_super) {

    __extends(CanvasImage, _super);

    function CanvasImage(x, y, width, height, url) {
      var self;
      this.url = url;
      CanvasImage.__super__.constructor.call(this, x, y, width, height);
      self = this;
      this.image = new Image();
      this.image.src = url;
      this.rotationAngle = 0;
      this.isCanvasImage = true;
    }

    CanvasImage.prototype.rotate = function(angle, rotationCenter) {
      CanvasImage.__super__.rotate.call(this, angle);
      return this.rotationAngle += angle;
    };

    CanvasImage.prototype.move = function(dx, dy) {
      CanvasImage.__super__.move.call(this, dx, dy);
      this.x += dx;
      return this.y += dy;
    };

    CanvasImage.prototype.draw = function() {
      var ctx;
      ctx = this.getContext();
      if (ctx) {
        if (this.rotationAngle && !(this.rotationAngle === 0)) {
          ctx.save();
          ctx.translate(this.center.x, this.center.y);
          ctx.rotate(this.rotationAngle);
          ctx.drawImage(this.image, this.x - this.center.x, this.y - this.center.y, this.width, this.height);
          return ctx.restore();
        } else {
          return ctx.drawImage(this.image, this.x, this.y, this.width, this.height);
        }
      }
    };

    return CanvasImage;

  })(Moshu.Canvas2D.Rectangle);

  window.Moshu.Canvas2D.PartialCanvasImage = (function(_super) {

    __extends(PartialCanvasImage, _super);

    function PartialCanvasImage(x, y, width, height, image) {
      PartialCanvasImage.__super__.constructor.call(this, x, y, width, height, image);
      this.clippingRectangle = {
        x: 0,
        y: 0,
        width: width,
        height: height
      };
    }

    PartialCanvasImage.prototype.setClippingRectangle = function(x, y, width, height) {
      return this.clippingRectangle = {
        x: x,
        y: y,
        width: width,
        height: height
      };
    };

    PartialCanvasImage.prototype.draw = function() {
      var ctx;
      ctx = this.getContext();
      if (ctx) {
        return ctx.drawImage(this.image, this.clippingRectangle.x, this.clippingRectangle.y, this.clippingRectangle.width, this.clippingRectangle.height, this.x, this.y, this.width, this.height);
      }
    };

    return PartialCanvasImage;

  })(Moshu.Canvas2D.CanvasImage);

  window.Moshu.Canvas2D.Sprite = (function(_super) {

    __extends(Sprite, _super);

    function Sprite(x, y, width, height, spriteRows, spriteCols, spriteWidth, spriteHeight, image) {
      Sprite.__super__.constructor.call(this, x, y, width, height, image);
      this.type = "image-sprite-2d";
      this.spriteWidth = spriteWidth;
      this.spriteHeight = spriteHeight;
      this.spriteRows = spriteRows;
      this.spriteCols = spriteCols;
      this.spriteRowIndex = 0;
      this.spriteColIndex = 0;
    }

    Sprite.prototype.setCurrentSprite = function(rowIndex, colIndex) {
      this.spriteRowIndex = rowIndex;
      return this.spriteColIndex = colIndex;
    };

    Sprite.prototype.setSpriteRow = function(rowIndex) {
      if (rowIndex < this.spriteRows && rowIndex >= 0) {
        return this.spriteRowIndex = rowIndex;
      }
    };

    Sprite.prototype.setSpriteCol = function(colIndex) {
      if (rowIndex < this.spriteCols && colIndex > 0) {
        return this.spriteColIndex = colIndex;
      }
    };

    Sprite.prototype.setNextSpriteOnRow = function() {
      if (this.spriteColIndex < this.spriteCols - 1) {
        return this.spriteColIndex++;
      } else {
        return this.spriteColIndex = 0;
      }
    };

    Sprite.prototype.setPrevSpriteOnRow = function() {
      if (this.spriteColIndex > 0) {
        return this.spriteColIndex--;
      } else {
        return this.spriteColIndex = this.spriteCols - 1;
      }
    };

    Sprite.prototype.draw = function() {
      var ctx;
      ctx = this.getContext();
      if (ctx) {
        return ctx.drawImage(this.image, this.spriteWidth * this.spriteColIndex, this.spriteHeight * this.spriteRowIndex, this.spriteWidth, this.spriteHeight, this.x, this.y, this.width, this.height);
      }
    };

    return Sprite;

  })(Moshu.Canvas2D.CanvasImage);

  window.Moshu.Canvas2D.CollisionManager = (function() {

    function CollisionManager() {}

    CollisionManager.prototype.getProjectionAxesForSAT = function(shape) {
      var axes, i, v1, v2, vector1, vector2, vertices, _i, _len;
      axes = [];
      vertices = shape.vertices();
      for (i = _i = 0, _len = vertices.length; _i < _len; i = ++_i) {
        v1 = vertices[i];
        v2 = null;
        if (i === vertices.length - 1) {
          v2 = vertices[0];
        } else {
          v2 = vertices[i + 1];
        }
        vector1 = new Moshu.Canvas2D.Vector([v1[0], v1[1]]);
        vector2 = new Moshu.Canvas2D.Vector([v2[0], v2[1]]);
        vector1.substract(vector2.vector);
        vector1.perp();
        axes.push(vector1);
      }
      return axes;
    };

    CollisionManager.prototype.getPolygonProjectionForSAT = function(shape, axis) {
      var i, max, min, v, val, vertices, _i, _len;
      vertices = shape.vertices();
      min = axis.dotProduct(vertices[0]);
      max = min;
      for (i = _i = 0, _len = vertices.length; _i < _len; i = ++_i) {
        v = vertices[i];
        val = axis.dotProduct([v.x, v.y]);
        if (min > val) {
          min = val;
        }
        if (max < val) {
          max = val;
        }
      }
      return [min, max];
    };

    CollisionManager.prototype.checkCollideSAT = function(shape1, shape2) {
      var axes1, axes2, axis, free, overlap, p1, p2, self, _i, _j, _len, _len1;
      self = this;
      axes1 = this.getProjectionAxesForSAT(shape1);
      axes2 = this.getProjectionAxesForSAT(shape2);
      free = false;
      for (_i = 0, _len = axes1.length; _i < _len; _i++) {
        axis = axes1[_i];
        p1 = self.getPolygonProjectionForSAT(shape1, axis);
        p2 = self.getPolygonProjectionForSAT(shape2, axis);
        overlap = false;
        if (p1[0] > p2[0] && p1[0] < p2[1]) {
          overlap = true;
        }
        if (p2[0] > p1[0] && p2[0] < p1[1]) {
          overlap = true;
        }
        if (!overlap) {
          free = true;
        }
      }
      if (!free) {
        for (_j = 0, _len1 = axes2.length; _j < _len1; _j++) {
          axis = axes2[_j];
          p1 = self.getPolygonProjectionForSAT(shape1, axis);
          p2 = self.getPolygonProjectionForSAT(shape2, axis);
          overlap = false;
          if (p1[0] > p2[0] && p1[0] < p2[1]) {
            overlap = true;
          }
          if (p2[0] > p1[0] && p2[0] < p1[1]) {
            overlap = true;
          }
          if (!overlap) {
            free = true;
          }
        }
      }
      return !free;
    };

    CollisionManager.prototype.checkCollide = function(shape1, shape2) {
      var collided, collision;
      if (shape1 && shape1.isPolygon && shape2 && shape2.isPolygon && shape1.vertices().length > 1 && shape2.vertices().length > 1) {
        collided = this.checkCollideSAT(shape1, shape2);
        if (collided) {
          collision = new Moshu.Canvas2D.Collision();
          collision.collider = shape1;
          collision.collidee = shape2;
          return collision;
        } else {
          return null;
        }
      } else {
        collision = new Moshu.Canvas2D.Collision();
        collision.collider = shape1;
        collision.collidee = shape2;
        return collision;
      }
    };

    return CollisionManager;

  })();

}).call(this);
